package com.app.module.email;

import java.io.File;
import java.net.URI;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import microsoft.exchange.webservices.data.*;
import com.app.configs.ResConfig;
import com.app.repository.REmail;
import org.apache.commons.lang.StringEscapeUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Created by Hendra on 12/30/2014.
 */
public class ModEmail extends ResConfig {

    private Logger logger = LoggerFactory.getLogger(ModEmail.class);

    private static ExchangeService service;
//    private List<MailTable> mailTables = new ArrayList<MailTable>();
//    private List<Map<String, Object>> msgDataList = new ArrayList<Map<String, Object>>();

    private String UUID;

    /**
     * Firstly check, whether "https://webmail.xxxx.com/ews/Services.wsdl" and
     * "https://webmail.xxxx.com/ews/Exchange.asmx" is accessible, if yes that
     * means the Exchange Webservice is enabled on your MS Exchange.
     */
    static {
        try {
            service = new ExchangeService(ExchangeVersion.Exchange2010);
            //service = new ExchangeService(ExchangeVersion.Exchange2007_SP1); //depending on the version of your Exchange.
        } catch (Exception e) {

        }
    }

    /**
     * Initialize the Exchange Credentials. Don't forget to replace the
     * "USRNAME","PWD","DOMAIN_NAME" variables.
     */
    public ModEmail() {
        try {

            service.setUrl(new URI("https://" + getSmtp_inbound_server() + "/ews/Exchange.asmx"));
            ExchangeCredentials credentials = new WebCredentials(getSmtp_inbound_username(), getSmtp_inbound_password());
            service.setCredentials(credentials);

        } catch (Exception e) {
            logger.error("Error", "Could not connect: " + e.getMessage());
        }

    }

    public ExchangeService connection() {
        try {
            service.setUrl(new URI("https://" + getSmtp_inbound_server() + "/ews/Exchange.asmx"));
            ExchangeCredentials credentials = new WebCredentials(getSmtp_inbound_username(), getSmtp_inbound_password());
            service.setCredentials(credentials);

        } catch (Exception e) {
            logger.error("Error", "Could not connect: " + e.getMessage());
        }

        return service;
    }

    /**
     * Reading one email at a time. Using Item ID of the email. Creating a
     * message data map as a return value.
     */
    public Map<String, Object> readEmailItem(Item item) {
        Map<String, Object> messageData = new HashMap<String, Object>();
        try {
            PropertySet propertySet = new PropertySet(BasePropertySet.FirstClassProperties, EmailMessageSchema.Attachments);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
            setUUID(GenerateShortUUID.next());
            String UUID = getUUID();
            Item itm = Item.bind(service, item.getId());
            // Item itm = Item.bind(service, item.getId(), PropertySet.getFirstClassProperties());
            EmailMessage emailMessage = EmailMessage.bind(service, itm.getId());

            if (emailMessage.getHasAttachments()) {
                for (Attachment attachment : emailMessage.getAttachments()) {
                    String FileExtension = getFileExtension(attachment.getName());
                    File TempFile = File.createTempFile(UUID + "_" + attachment.getName(), FileExtension);
                    System.out.println("attachment >>>>>>>>>>>>>>>>>>>>>>> " + attachment.getName() + "+++++++++++++ " + TempFile.getAbsolutePath());
                    messageData.put("attachment", TempFile.getAbsolutePath());
                }
                createAttachment(emailMessage.getAttachments(), UUID);
            }
            messageData.put("fromAddress", emailMessage.getFrom().getAddress() != null ? emailMessage.getFrom().getAddress() : "");
            messageData.put("hasAttachment", emailMessage.getHasAttachments());
//            String a = "[" + createAttachment(emailMessage.getAttachments(), UUID) + "{\"fileName\" : \"afany\"}" + "]";

//            messageData.put("attachment", emailMessage.getHasAttachments() ? a : "");
            messageData.put("emailItemId", UUID);
            messageData.put("isRead", emailMessage.getIsRead());
            messageData.put("subject", emailMessage.getSubject());
            messageData.put("senderName", emailMessage.getSender().getName());
//            Date dateTimeCreated = emailMessage.getDateTimeCreated();
            sdf.format(emailMessage.getDateTimeCreated());
            messageData.put("SendDate", sdf.format(emailMessage.getDateTimeCreated()));
//            Date dateTimeRecieved = emailMessage.getDateTimeReceived();
            messageData.put("ReceivedDate", sdf.format(emailMessage.getDateTimeReceived()));
            messageData.put("Size", emailMessage.getSize() + "");
            messageData.put("emailBody", StringEscapeUtils.escapeHtml(emailMessage.getBody().toString()).replaceAll("\\p{Cntrl}", "\\\\\"").replaceAll(":", "&#58;"));

//            messageData.put("emailBody", emailMessage.getBody().toString()
//                    .replaceAll("\"", "\\\\\"")
//                    .replaceAll(":", "&#58;"));
            emailMessage.setIsRead(true);
        } catch (Exception e) {
            logger.error("Error", "Read email failed: " + e.getMessage());
        }
        return messageData;
    }

//    public Map<String, Object> readEmailItem(ItemId itemId) {
//        Map<String, Object> messageData = new HashMap<String, Object>();
//        try {
//            PropertySet propertySet = new PropertySet(BasePropertySet.FirstClassProperties, EmailMessageSchema.Attachments);
//            propertySet.setRequestedBodyType(BodyType.Text);
//            setUUID(new GenerateShortUUID().next());
//            Item itm = Item.bind(service, itemId, propertySet);
//
//            EmailMessage emailMessage = EmailMessage.bind(service, itm.getId(), propertySet);
////            messageData.put("emailItemId", getUUID());
////            messageData.put("isRead", emailMessage.getIsRead());
////            messageData.put("subject", emailMessage.getSubject().toString());
////            messageData.put("fromAddress", emailMessage.getFrom().getAddress().toString());
////            messageData.put("senderName", emailMessage.getSender().getName().toString());
////            Date dateTimeCreated = emailMessage.getDateTimeCreated();
////            messageData.put("SendDate", dateTimeCreated.toString());
////            Date dateTimeRecieved = emailMessage.getDateTimeReceived();
////            messageData.put("ReceivedDate", dateTimeRecieved.toString());
////            messageData.put("Size", emailMessage.getSize() + "");
//            messageData.put("emailBody", emailMessage.getBody().toString());
//            if (emailMessage.getHasAttachments()) {
//                createAttachment(emailMessage.getAttachments());
//            }
//            //emailMessage.setIsRead(true);
//        } catch (Exception e) {
//            logger.error("Error", "Read email failed: " + e.getMessage());
//        }
//        return messageData;
//    }
    /**
     * Number of email we want to read is defined as NUMBER_EMAILS_FETCH,
     *
     * @param service
     * @return 
     */
    public List<Map<String, Object>> readEmails(ExchangeService service) {
        List<Map<String, Object>> msgDataList = new ArrayList<Map<String, Object>>();
        REmail email = new REmail();
        try {
//            SimpleDateFormat formatter = new SimpleDateFormat("dd-MMM-yyyy");
            ItemView view = new ItemView(Integer.parseInt(getSmtp_email_limit()));
            view.getOrderBy().add(ItemSchema.DateTimeReceived, SortDirection.Ascending);
            SearchFilter itemFilter = new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false);
            SearchFilter filters = new SearchFilter.IsEqualTo(EmailMessageSchema.HasAttachments, true);
//            Folder folder = Folder.bind(service, WellKnownFolderName.Inbox);
            FolderId id = new FolderId(WellKnownFolderName.Inbox);
            Mailbox mailbox = Mailbox.getMailboxFromString("POB2B.callcenter@aplcare.com");
            FolderId folderId = new FolderId(WellKnownFolderName.Inbox, mailbox);
//            FindItemsResults<Item> results = service.findItems(folder.getId(), new ItemView(Integer.parseInt(getSmtp_email_limit())));
            FindItemsResults<Item> results = service.findItems(id, itemFilter, view);
//            service.loadPropertiesForItems(results, new PropertySet(BasePropertySet.FirstClassProperties, EmailMessageSchema.Attachments));

            int i = 1;
            for (Item item : results) {
                String json = "{";
                Map<String, Object> messageData = readEmailItem(item);

                for (Map.Entry<String, Object> entry : messageData.entrySet()) {
                    String string = entry.getKey();
                    Object object = entry.getValue();
                    json += "\"" + string + "\" : " + "\"" + object.toString() + "\",";
                }
                json += "\"test\" : \"123\"}";
                if (!json.equals("{\"test\" : \"123\"}")) {
                    email.post(json);
                    email = new REmail();
                }
//                msgDataList.add(messageData);
            }

        } catch (Exception e) {
            logger.error("Error", "Read email failed" + e.getMessage());
        }
        return msgDataList;
    }

    /**
     * Reading one appointment at a time. Using Appointment ID of the email.
     * Creating a message data map as a return value.
     */
    public Map<String, Object> readAppointment(Appointment appointment) {
        Map<String, Object> appointmentData = new HashMap<String, Object>();
        try {
            appointmentData.put("appointmentItemId", appointment.getId().toString());
            appointmentData.put("appointmentSubject", appointment.getSubject());
            appointmentData.put("appointmentStartTime", appointment.getStart() + "");
            appointmentData.put("appointmentEndTime", appointment.getEnd() + "");
            //appointmentData.put("appointmentBody", appointment.getBody().toString());
        } catch (ServiceLocalException e) {
            logger.error("Error", "Read appointment failed" + e.getMessage());
        }
        return appointmentData;
    }

    /**
     * Number of Appointments we want to read is defined as NUMBER_EMAILS_FETCH,
     * Here I also considered the start data and end date which is a 30 day
     * span. We need to set the CalendarView property depending upon the need of
     * ours.
     */
    public List<Map<String, Object>> readAppointments() {
        List<Map<String, Object>> apntmtDataList = new ArrayList<Map<String, Object>>();
        Calendar now = Calendar.getInstance();
        Date startDate = Calendar.getInstance().getTime();
        now.add(Calendar.DATE, 30);
        Date endDate = now.getTime();
        try {
            CalendarFolder calendarFolder = CalendarFolder.bind(service, WellKnownFolderName.Calendar, new PropertySet());
            CalendarView cView = new CalendarView(startDate, endDate, 5);
            cView.setPropertySet(new PropertySet(AppointmentSchema.Subject, AppointmentSchema.Start, AppointmentSchema.End));	// we can set other properties as well depending upon our need.
            FindItemsResults<Appointment> appointments = calendarFolder.findAppointments(cView);

            int i = 1;
            List<Appointment> appList = appointments.getItems();
            for (Appointment appointment : appList) {
                System.out.println("\nAPPOINTMENT #" + (i++) + ":");
                Map<String, Object> appointmentData = new HashMap<String, Object>();
                appointmentData = readAppointment(appointment);
                System.out.println("subject : " + appointmentData.get("appointmentSubject").toString());
                System.out.println("On : " + appointmentData.get("appointmentStartTime").toString());
                apntmtDataList.add(appointmentData);
            }
        } catch (Exception e) {
            logger.error("Error", "Read appointment failed" + e.getMessage());
        }
        return apntmtDataList;
    }

    public void createAttachment(AttachmentCollection attachments, String UUID) throws Exception {
////        List<Map<String, Object>> msgDataList = new ArrayList<Map<String, Object>>();
//        String json = "";
//        for (Attachment attachment : attachments) {
//            Map<String, Object> messageData = new HashMap<String, Object>();
//
//            String FileExtension = getFileExtension(attachment.getName());
//            File TempFile = File.createTempFile(UUID + "_" + attachment.getName(), FileExtension);
////            attachment.load(TempFile.getAbsolutePath());
//            messageData.put("fileName", UUID + "_" + attachment.getName());
//            messageData.put("path", TempFile.getAbsolutePath());
//            messageData.put("fileExtension", FileExtension);
//            json = "{";
//            for (Map.Entry<String, Object> entry : messageData.entrySet()) {
//                String string = entry.getKey();
//                Object object = entry.getValue();
//                json += "\"" + string + "\" : " + "\"" + object.toString() + "\",";
//            }
//            json += "\"type\" : \"inbox\"},";
//        }
        for (int i = 0; i < attachments.getCount(); i++) {
            Map<String, Object> messageData = new HashMap<String, Object>();
//            Attachment attachment = attachments.getPropertyAtIndex(i);
            FileAttachment attachment = (FileAttachment) attachments.getPropertyAtIndex(i);
            String FileExtension = getFileExtension(attachment.getName());
            File TempFile = File.createTempFile(UUID + "_" + attachment.getName(), FileExtension);
            attachment.load("C:\\Users\\afany\\Documents\\PTPN-coba\\v2\\apl-db-migrator\\attachment\\" + attachment.getFileName());
//            messageData.put("fileName", UUID + "_" + attachment.getName());
//            messageData.put("path", attachment.getContentLocation());
//            messageData.put("fileExtension", FileExtension);
//            json = "{";
//            for (Map.Entry<String, Object> entry : messageData.entrySet()) {
//                String string = entry.getKey();
//                Object object = entry.getValue();
//                json += "\"" + string + "\" : " + "\"" + object.toString() + "\",";
//            }
//            json += "\"type\" : \"inbox\"},";
////            msgDataList.add(messageData);
        }
//        return json;
    }

    private String getFileExtension(String name) {
        int lastIndexOf = name.lastIndexOf(".");
        if (lastIndexOf == -1) {
            return ""; // empty extension
        }
        return name.substring(lastIndexOf);
    }

    public void getAttachmentData(String Filename) {
        File path = new File(System.getProperty("java.io.tmpdir"));
        File[] files = path.listFiles();
        for (int i = 0; i < files.length; i++) {
            if (files[i].isFile() && Pattern.compile(Filename).matcher(files[i].getName()).find()) {
                System.out.println(files[i].getAbsolutePath());
                files[i].deleteOnExit();
            }
        }
    }

    private String getUUID() {
        return UUID;
    }

    private void setUUID(String UUID) {
        this.UUID = UUID;
    }

    public void checkOutbox() throws JSONException {
        REmail email = new REmail();
        email.get(null);
        if (email.getMessages() != null) {
            JSONObject o = new JSONObject(email.getMessages());
            if (!o.toString().equals("{}") || o != null) {
                System.out.println("masuk send");
                if (sendEmail(StringEscapeUtils.unescapeHtml(o.getString("message")), o.getString("subject"),
                        o.getString("email_address"),
                        "Call.Center@aplcare.com",
                        connection())) {
                    System.out.println("berhasil send");
                    email = new REmail();
                    email.put(String.valueOf(o.getInt("email_id")));
                }
            }
        }
    }

    public boolean sendEmail(String body, String subject, String recipients, String from, ExchangeService service) {
        try {
            EmailMessage replymessage = new EmailMessage(service);
            EmailAddress fromEmailAddress = new EmailAddress(from);
            replymessage.setFrom(fromEmailAddress);
            replymessage.getToRecipients().add(recipients);
            replymessage.setInReplyTo(recipients);
            replymessage.setSubject(subject);
            replymessage.setBody(new MessageBody(body));
            replymessage.send();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("" + e);
            return false;
        }

    }
//
//    public List<Map<String, Object>> getListMail() {
//        return msgDataList;
//    }
}
